package cn.wps.moffice.main.framework.datastorage;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build;
import android.util.Base64;
import android.util.Log;
import cn.wps.moffice.OfficeApp;

/**
 * 持久化数据存储
 * 封装SharedPreferences进行文件存储
 * (请不要直接调用该单例，通过PersistentsMgr进行使用)
 * @author zhangzuobing
 */
public class SPPersistent implements IPersistent {
	private static final String TAG = "SPPersistent";
    private static SPPersistent _instance;
    private int MODE_MULTI_PROCESS = 4;  //Context.MODE_MULTI_PROCESS
    private int preferencesModel = (Build.VERSION.SDK_INT > 10) ? MODE_MULTI_PROCESS: Context.MODE_PRIVATE;

    private static final String DEFAULT_SAVE_FILE = "public_default"; // public存储位置, 存储简单数据, 共享一个文件
    private SharedPreferences publicSp; // 支持多进程的 SharedPreferences

    public static SPPersistent getInstance() {
        if (_instance == null) {
            _instance = new SPPersistent();
        }
        return _instance;
    }

    private void getPublicSp() {
          publicSp = OfficeApp.getInstance().getSharedPreferences(DEFAULT_SAVE_FILE, preferencesModel);
    }

    /* 如果有需求再扩展数据监听
     * public interface OnPersistentChangeListener {
        void onPersistentChanged(String fileName, String key);
    }*/

    // ============public存储 =============
    @Override
    public boolean putBoolean(IPersistentPublicKeys key, boolean value) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.putBoolean(key.getString(), value);
        boolean rst = editor.commit();
        return rst;
    }

    @Override
    public boolean putFloat(IPersistentPublicKeys key, float value) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.putFloat(key.getString(), value);
        boolean rst = editor.commit();
        return rst;
    }

    @Override
    public boolean putInt(IPersistentPublicKeys key, int value) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.putInt(key.getString(), value);
        boolean rst = editor.commit();
        return rst;
    }

    @Override
    public boolean putLong(IPersistentPublicKeys key, long value) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.putLong(key.getString(), value);
        boolean rst = editor.commit();
        return rst;
    }

    @Override
    public boolean putString(IPersistentPublicKeys key, String value) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.putString(key.getString(), value);
        boolean rst =  editor.commit();
        return rst;
    }

    @Override
    public boolean remove(IPersistentPublicKeys key) {
    	getPublicSp();
        SharedPreferences.Editor editor = publicSp.edit();
        editor.remove(key.getString());
        boolean rst = editor.commit();
        return rst;
    }

    // =====get======
    @Override
    public boolean contains(IPersistentPublicKeys key) {
    	getPublicSp();
        boolean rst = publicSp.contains(key.getString());
        return rst;
    }

    @Override
    public boolean getBoolean(IPersistentPublicKeys key, boolean defValue) {
    	getPublicSp();
    	boolean rst =defValue;
    	try {
			rst = publicSp.getBoolean(key.getString(), defValue);
		} catch (ClassCastException ex) {  //几率很小，如被篡改类型
			remove(key);
			Log.w(TAG, ex.getMessage(), ex);
		}
        return rst;
    }

    @Override
    public float getFloat(IPersistentPublicKeys key, float defValue) {
    	getPublicSp();
    	float rst = defValue;
    	try {
			rst = publicSp.getFloat(key.getString(), defValue);
		} catch (ClassCastException ex) {
			remove(key);
			Log.w(TAG, ex.getMessage(), ex);
		}
        return rst;
    }

    @Override
    public int getInt(IPersistentPublicKeys key, int defValue) {
    	getPublicSp();
    	int rst = defValue;
    	try {
			rst = publicSp.getInt(key.getString(), defValue);
		} catch (ClassCastException ex) {
			remove(key);
			Log.w(TAG, ex.getMessage(), ex);
		}
        return rst;
    }

    @Override
    public long getLong(IPersistentPublicKeys key, long defValue) {
    	getPublicSp();
    	long rst = defValue;
    	try {
			rst = publicSp.getLong(key.getString(), defValue);
		} catch (ClassCastException ex) {
			remove(key);
			Log.w(TAG, ex.getMessage(), ex);
		}
        return rst;
    }

    @Override
    public String getString(IPersistentPublicKeys key, String defValue) {
    	getPublicSp();
    	String rst = defValue;
		try {
			rst = publicSp.getString(key.getString(), defValue);
		} catch (ClassCastException ex) {
			remove(key);
			Log.w(TAG, ex.getMessage(), ex);
		}
        return rst;
    }
    // ============public存储end =============

    // ============模块私有存储=============
    @Override
    public boolean containsModel(String fileName, String key) {
        SharedPreferences modelSp = OfficeApp.getInstance().getSharedPreferences(fileName, preferencesModel);
        return modelSp.contains(key);
    }

    /*
     * 存储复杂对象,(存放到指定的独立文件)
     */
    @Override
    public <T extends DataModel> boolean putModel(String fileName, String key, T model) {
        return putModelSerializable(fileName, key, model);
    }

    @Override
    public <T extends DataModel> boolean  putModels(String fileName, String key, ArrayList<T> models) {
        return putModelSerializable(fileName, key, models);
    }

    @Override
    public <K, T extends DataModel> boolean putHashModels(String fileName, String key, HashMap<K, T> models) {
        return putModelSerializable(fileName, key, models);
    }

    private boolean putModelSerializable(String fileName, String key, Serializable model) {
        boolean rst = false;

         SharedPreferences modelSp = OfficeApp.getInstance().getSharedPreferences(fileName, preferencesModel);

         ByteArrayOutputStream os = new ByteArrayOutputStream();
         ObjectOutputStream oos = null;
         try {
             oos = new ObjectOutputStream(os);
             oos.writeObject(model);
             byte[] bytes = os.toByteArray();
             String modelBase64 = Base64.encodeToString(bytes, Base64.DEFAULT);
             Editor editor = modelSp.edit();
             editor.putString(key, modelBase64);
             rst = editor.commit();
         } catch (IOException e) {
 			 Log.w(TAG, e.getMessage(), e);
        } finally {
            try {
                if (null != oos) {
                    oos.close();
                }
                if (null != os) {
                    os.close();
                }
            } catch (IOException e) {
            }
        }
         return rst;
    }

    /*
     * 从指定文件获取复杂对象
     */
    @Override
    public <T extends DataModel> T getModel(String fileName, String key) {
        return getModelSerializable(fileName, key);
    }

    @Override
    public <T extends DataModel> ArrayList<T> getModels(String fileName, String key) {
         return getModelSerializable(fileName, key);
    }

    @Override
    public <K, T extends DataModel> HashMap<K, T> getHashModels(String fileName, String key) {
        return getModelSerializable(fileName, key);
    }

    @SuppressWarnings("unchecked")
    private <T extends Serializable> T  getModelSerializable(String fileName, String key) {
        Object model = null;

        SharedPreferences modelSp = OfficeApp.getInstance().getSharedPreferences(fileName, preferencesModel);
        String modelBase64 =modelSp.getString(key, "");
        if (modelBase64 == null || modelBase64.length() == 0) {
            return null;
        }
        byte[] modelBytes = null;
        try {
        	modelBytes= Base64.decode(modelBase64, Base64.DEFAULT);
        } catch (IllegalArgumentException e) { //bad base-64, if the input contains incorrect padding 
			Log.w(TAG, e.getMessage(), e);
        }        
        if (modelBytes == null || modelBytes.length == 0) {
            return  null;
        }
        ByteArrayInputStream is = new ByteArrayInputStream(modelBytes);
        ObjectInputStream objis = null;
        try {
            objis = new ObjectInputStream(is);
            model = objis.readObject();
        } catch(OptionalDataException e) {
			Log.w(TAG, e.getMessage(), e);
        } catch(IOException e) {
			Log.w(TAG, e.getMessage(), e);
        } catch (ClassNotFoundException e) {
			Log.w(TAG, e.getMessage(), e);
        } finally {
            try {
                if (null != objis) {
                    objis.close();
                }
                if (null != is) {
                    is.close();
                }
            } catch (IOException e) {
            }
        }
        return model == null ? null : (T) model;
    }

    @Override
    public boolean removeModel(String fileName, String key) {
         SharedPreferences modelSp = OfficeApp.getInstance().getSharedPreferences(fileName, preferencesModel);
         SharedPreferences.Editor editor = modelSp.edit();
         editor.remove(key);
         boolean rst = editor.commit();
         return rst;
    }

    // ============私有存储end============
}
